package org.hive.data
{
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.*;
	import flash.media.SoundLoaderContext;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.text.TextField;
	import org.hive.managers.plugin.LoadManager;
	
	import org.hive.data.*;
	import org.hive.events.LoaderSetEvent;
	import org.hive.managers.StateManager;
	
	public class LoaderSet extends EventDispatcher
	{
		private var __LOADERS:Array = new Array();
		public function get loaders():Array { return __LOADERS; }
		public function get length():uint { return __LOADERS.length; }
		
		private var __name:String;
		public function get name():String { return __name; }
		
		private var __isLoading:Boolean = false;
		private var __isLoaded:Boolean = false;
		public function get isLoading():Boolean { return __isLoading; }
		
		private var __loaderSetIncrementPercent : Number;
		public function get incrementPercent():Number { return __loaderSetIncrementPercent; }
		
		private var __overallPercentArray : Array = [];
		private var __overallPercentComplete : Number = 0;
		public function get percent():Number { return __overallPercentComplete; }
		
		private var __loaderSetPosition:Number = 0;
		
		public function LoaderSet( nm:String, incrementPercent:Number, ...args )
		{
			__name = nm;
			__loaderSetIncrementPercent = incrementPercent;
			
			var noDupArray:Array = new Array();
			
			if( args[0] is Array )
			{
				noDupArray = removeDuplicates(args[0]);
				__LOADERS = noDupArray;
			}
			else
			{
				noDupArray = removeDuplicates(args);
				for( var i:Number=0; i<noDupArray.length; i++ ){
					__LOADERS[i] = noDupArray[i].toString();
				}
			}
			
		}
		
		public function add( ...args ):void
		{
			var i:Number;
			
			// check to see if the loader has already been added
			// if it has been added, don't add it again
			
			if( args[0] is Array ){
				
				args[0] = removeDuplicates(args[0]);
				
				for (i=0; i < args[0].length; i++) 
				{
					
					__LOADERS.push( args[0][i] )
				}
			} else {
				
				args = removeDuplicates(args);
				
				for (i= 0; i < args.length; i++) 
				{
					__LOADERS.push( args[i] )
				}
			}
		}
		
		private function removeDuplicates( loaderArray:Array ):Array
		{
			var noDuplicatesArray:Array = new Array();
			
			var is_unique:Function = function (item:*, index:int, array:Array):Boolean 
			{
				return array.indexOf(item,index + 1) == -1;
			};

			noDuplicatesArray = loaderArray.filter(is_unique);
			
			return noDuplicatesArray;
		}
		
		//METHODS
		public function startLoad():void
		{
			quedLoader = __LOADERS[0];

			
			for( var i:Number = 0; i<__LOADERS.length; i++) {
				__overallPercentArray[i] = 0;
				 LoadManager.getLoaderByName( __LOADERS[i] ).positionInLoadSet = i;
			}
			__isLoading = true;

			loadNextInSet();
		}
		
		public var quedLoader:String = "";
		
		private function loadNextInSet():void
		{
			var elgibleLoaders:Array = __LOADERS.filter( checkIfQuedIsLoading );
			var quedIndex:Number = elgibleLoaders.indexOf( quedLoader );
			
			var nextIndex:Number = (quedIndex + 1 == elgibleLoaders.length ) ? 0 : quedIndex + 1;
			
						
			load( LoadManager.getLoaderByName( elgibleLoaders[ quedIndex ] ) );
			quedLoader = elgibleLoaders[ nextIndex ];
			
		}
		
		private function checkIfQuedIsLoading( item:*, index:int, array:Array):Boolean
		{
		
			var quedIndex:Number = __LOADERS.indexOf( item );
			var quedLoader:* = LoadManager.getLoaderByName( __LOADERS[quedIndex] );
			
			return !quedLoader.isLoading;
		}
		
		public function forceLoad( loaderName:String ):void
		{
			quedLoader = loaderName;
			loadNextInSet();
		}
		
		
		private function load( ldr:* ):void
		{
			if( ldr is LoaderData ){
				if( !ldr.isLoaded && !ldr.isLoading ){
					//trace("LoaderSet :: load() : "+ldr.name + ' : ' + ldr.URL);
					try {
						ldr.load( ldr.URL, new LoaderContext( ldr.checkPolicy, ApplicationDomain.currentDomain ) );
					} catch( e:Error ){
						trace("LoaderSet :: load() : "+e);
					}
					configureListeners( ldr.contentLoaderInfo );
					ldr.isLoading = true;
				}
			}
			else if ( ldr is SoundData || ldr is URLData ){
				if( !ldr.isLoading && !ldr.isLoading  ){
					ldr.load( ldr.URL );
					configureListeners( ldr );
					ldr.isLoading = true;
				}
			}
		}
		
		
		
		private function configureListeners(dispatcher:IEventDispatcher):void 
		{
            dispatcher.addEventListener(Event.COMPLETE, handleComplete, false, 0, true);
            dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler, false, 0, true);
            dispatcher.addEventListener(Event.INIT, handleInit, false, 0, true);
            dispatcher.addEventListener(IOErrorEvent.IO_ERROR, handleError, false, 0, true);
            dispatcher.addEventListener(Event.OPEN, openHandler, false, 0, true);
            dispatcher.addEventListener(ProgressEvent.PROGRESS, handleProgress, false, 0, true);
            dispatcher.addEventListener(Event.UNLOAD, unLoadHandler, false, 0, true);
        }
        private function removeListeners(dispatcher:IEventDispatcher):void 
		{
            dispatcher.removeEventListener(Event.COMPLETE, handleComplete);
            dispatcher.removeEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
            dispatcher.removeEventListener(Event.INIT, handleInit);
            dispatcher.removeEventListener(IOErrorEvent.IO_ERROR, handleError);
            dispatcher.removeEventListener(Event.OPEN, openHandler);
            dispatcher.removeEventListener(ProgressEvent.PROGRESS, handleProgress);
            dispatcher.removeEventListener(Event.UNLOAD, unLoadHandler);
        }
		
		
		
		private function changeOverallPercent( percentOfLoaderData:Number, positionInLoadSet:int ):void
		{
			//TextField(StateManager.layoutManager.getChildByName("trace")).appendText( "Percent:: "+ percentOfLoaderData+"\n");
			
			__overallPercentArray[positionInLoadSet] = Math.round( percentOfLoaderData );
			var num : Number = 0;
			for (var i:Number = 0; i < __LOADERS.length; i++) {
				num += __overallPercentArray[i];
		    }
			
			__overallPercentComplete = num / __LOADERS.length;

			
			
			// trace("LoadManager :: OVERALL %: "+__overallPercentComplete);
			dispatchEvent( new LoaderSetEvent( LoaderSetEvent.ON_CHANGE, Math.round(__overallPercentComplete) ) );
		}
		
		public function setPause( name:String ):void
		{
			__isLoading = false;
			for each( var element in __LOADERS ){
				if (element != name &&  LoadManager.getLoaderByName( element ).isLoading ){
					
					trace("LoaderSet :: close(): "+element);
					try {
						
						LoadManager.getLoaderByName( element ).close();
						removeListeners( LoadManager.getLoaderByName( element ) );
					} catch( e:Error ){
						trace("LoaderSet :: close(): "+e);
					}
				}
			}
		}
		
		public function setResume():void
		{
			__isLoading = true;
			__LOADERS.forEach( resume );
		}
		
		private function pause( element:*, index:Number, arr:Array ):void
		{
			if( LoadManager.getLoaderByName( element ).isLoading   ){
				try {
					removeListeners( LoadManager.getLoaderByName( element ) );
					try {
						LoadManager.getLoaderByName( element ).close();
					} catch( e:Error ){
						trace(e);
					}
				} catch( e:Error ){
					trace(e);
				}
			}
			
		}
		
		private function resume( element:*, index:Number, arr:Array ):void
		{
			if( LoadManager.getLoaderByName( element ).isLoading )
			LoadManager.getLoaderByName( element ).load( LoadManager.getLoaderByName( element ).URL );
		}
		
		//EVENTS
		private function httpStatusHandler(e:HTTPStatusEvent):void {
			//trace("LoadManager :: httpStatusHandler : "  + LoadManager.getLoaderByContent(e.currentTarget).name);
        }

        private function openHandler(e:Event):void {
			LoadManager.getLoaderByContent(e.currentTarget).isLoading = true;
			
			//trace("LoadManager :: openHandler : "  + LoadManager.getLoaderByContent(e.currentTarget).name);
        }

        private function unLoadHandler(e:Event):void {
			//trace("LoadManager :: unLoadHandler : "  + LoadManager.getLoaderByContent(e.currentTarget).name);
        }
		
		private function handleProgress( e:ProgressEvent ):void
		{
			var percent : Number = Math.round( (e.bytesLoaded / e.bytesTotal) * 100 );
			
			//TextField(StateManager.layoutManager.getChildByName("trace")).appendText( "Percent::"+e.bytesLoaded+" t:"+e.bytesTotal+" p:"+ percent +"\n");
			
			if( percent <= 100 ) 
				changeOverallPercent( percent, LoadManager.getLoaderByContent( e.currentTarget ).positionInLoadSet );
			else if( percent > 100 )
				changeOverallPercent( 100, LoadManager.getLoaderByContent( e.currentTarget ).positionInLoadSet );
				
			if( percent >= __loaderSetIncrementPercent && !LoadManager.getLoaderByContent(e.currentTarget).incrementPassed ){
				LoadManager.getLoaderByContent(e.currentTarget).incrementPassed = true;
				
				loadNextInSet();
			}
			
			
		}
		
		private function checkHandlers( element:*, index:Number, arr:Array):Boolean
		{
			return LoadManager.getLoaderByName(element).isLoaded;
		}
		
		private function handleComplete( e:Event ):void
		{
			//trace("LoadManager :: Complete : " + LoadManager.getLoaderByContent(e.currentTarget).name);
			
			var ldr:* = LoadManager.getLoaderByContent(e.currentTarget);

			if( ldr is LoaderData )	removeListeners( ldr.contentLoaderInfo );
			else if ( ldr is SoundData || ldr is URLData ){
				removeListeners( ldr );
				dispatchEvent( new LoaderSetEvent( LoaderSetEvent.ON_ELEMENT_ADDED, __overallPercentComplete, ldr ) );
			}
			ldr.isLoading = false;
			ldr.isLoaded = true;
			
					
			if( __LOADERS.filter( checkHandlers ).length == __LOADERS.length  )
			{
				__isLoading = false;
				__isLoaded = true;
				dispatchEvent( new LoaderSetEvent( LoaderSetEvent.ON_COMPLETE, __overallPercentComplete, null, null, null, __LOADERS ) );
			}
		}
		
		private function handleInit( e:Event ):void
		{
			//trace("LoadManager :: init : " + LoadManager.getLoaderByContent(e.currentTarget).name);
			dispatchEvent( new LoaderSetEvent( LoaderSetEvent.ON_ELEMENT_ADDED, __overallPercentComplete, LoadManager.getLoaderByContent(e.currentTarget) ) );
		}
		
		private function handleError( e:IOErrorEvent ):void
		{
			trace("LoadManager :: handleError : " + e );
			
			dispatchEvent( new LoaderSetEvent( LoaderSetEvent.ON_ERROR, __overallPercentComplete, e.currentTarget, e ) );
			loadNextInSet();
		}
		
	}
	
}